/*
 * @Author: 13938960424 1758142861@qq.com
 * @Date: 2023-10-25 13:56:08
 * @LastEditors: 13938960424 1758142861@qq.com
 * @LastEditTime: 2023-10-25 17:11:52
 * @FilePath: /sjf/new-xshell/muduo/pre_knowledge/timer_wheel.cc
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <unordered_map>
#include <functional>
#include <unistd.h>

using TaskFuc = std::function<void()>;
using ReleaseFunc = std::function<void()>;

class TimerTask
{
public:
    TimerTask(uint64_t id,uint32_t time,const TaskFuc& cb)
    :_id(id),_timeout(time),_task_cb(cb),_canceled(false)
    {}
    ~TimerTask()
    {
        //先判断该任务是否被取消了,没被取消就执行相应的任务
        if(_canceled == false)
            _task_cb();
        _release();
    }
    void set_canceled() { _canceled = true; }
    void set_release(const ReleaseFunc& func) { _release = func; }
    uint32_t get_delay_timer() { return _timeout; }
private:
    uint64_t _id; //定时任务id
    uint32_t _timeout;//定时时间
    TaskFuc _task_cb;//定时任务的回调函数
    ReleaseFunc _release;//删除该定时任务信息
    bool _canceled;//取消定时任务(默认为false -- 不取消, true -- 取消)
};

using WeakTask = std::weak_ptr<TimerTask>;//保存轮子中的任务信息
using PtrTask = std::shared_ptr<TimerTask>;//对应轮子中的每个任务
class TimerWheel
{
public:
    TimerWheel()
    :_tick(0),_capacity(60),_wheel(_capacity)
    {}
    ~TimerWheel()
    {}
    //新增定时任务
    void add_timer(uint64_t id,uint32_t time,const TaskFuc& cb)
    {
        PtrTask pt(new TimerTask(id,time,cb));
        pt->set_release(std::bind(&TimerWheel::remove_timer_task,this,id));
        int pos = (_tick + time) % _capacity;
        _wheel[pos].push_back(pt);
        _timers[id] = WeakTask(pt);
    }
    //(刷新/延时)定时任务
    void refresh_timer(uint64_t id)
    {
        auto it = _timers.find(id);
        if(it == _timers.end())
            return;
        PtrTask pt = it->second.lock();//lock获取weak_ptr管理对象对应的shared_ptr
        uint32_t delay = pt->get_delay_timer();
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);
    }
    //移除定时任务
    void canceled_timer(uint64_t id)
    {
        auto it = _timers.find(id);
        if(it == _timers.end())
            return;
        PtrTask pt = it->second.lock();//lock获取weak_ptr管理对象对应的shared_ptr
        if(pt) pt->set_canceled();
    }
    void run_timer_task()
    {
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear();//清除当前位置的信息,让该tick的shard_ptr释放掉,去执行析构函数
    }
private:
    //根据id判断该任务是否存在
    void remove_timer_task(uint64_t id)
    {
        auto it = _timers.find(id);
        if(it != _timers.end())
            _timers.erase(id);
    }
private:
    int _tick;//当前位置
    int _capacity;//轮子最大延时时间
    std::vector<std::vector<PtrTask>> _wheel;//二维数组存放的是每个tick下存放的定时任务信息
    std::unordered_map<uint64_t,WeakTask> _timers;//通过任务id获取到任务
};

class Test
{
public:
     Test() { std::cout << "构造" << std::endl; }
    ~Test() { std::cout << "析构" << std::endl; }
};

void del_test(Test* tt)
{
    delete tt;
}

int main()
{
    TimerWheel tw;
    Test* t = new Test();
    tw.add_timer(1,5,std::bind(del_test,t));
    for(int i = 0; i < 5; i++)
    {
        sleep(1);
        tw.refresh_timer(1);
        tw.run_timer_task();
        std::cout << "刷新了定时任务,需要重新等待5s钟后才会执行销毁" << std::endl;
    }
    int i = 1;
    while(1)
    {
        sleep(1);
        std::cout << "I:[%d]--------------" << i++ << std::endl;
        tw.run_timer_task();
        if(i == 2) tw.canceled_timer(1);
    }
    return 0;
}